#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dfs.h>
#include <errno.h>
#include <limits.h>
#include <unistd.h>
#include "dfs_net.h"
#include "dfs_service.h"
#include "dfs_multies.h"
#include "dfs_messages.h"
#include "dfs_transfer_file_send.h"
#include "dfs_transfer_file_recv.h"

/* Builds a message according to it's parameters */
int build_message(dfs_message *m,const char *sender,const char *receiver,int kind,int type,const char *data){
	int r;
	/* First clear message */
	memset(m->sender,0,sizeof(m->sender));
	memset(m->receiver,0,sizeof(m->receiver));
	memset(m->data,0,sizeof(m->data));
	
	/*Form message */
	r = sprintf(m->sender,"%s",sender);
	if( r < 0) return (ERROR);
	r = sprintf(m->receiver,"%s",receiver);
	if( r < 0) return (ERROR);
	m->kind = kind;
	m->type = type;
	r = sprintf(m->data,"%s",data);
	if (r< 0) return (ERROR);
	
	/* message built */
	return (OK);
}

/* Serializes a message to be sent among servers*/
int message_to_string(dfs_message *m,char *str){
	int r;
	r = sprintf(str,"%s|%s|%d|%d[%s",m->sender
									,m->receiver
									,m->kind
									,m->type
									,m->data);
									
	if(r < 0 ) return (ERROR);
	else return (OK);
}


/* Deserializes a message sent among servers */
int string_to_message(dfs_message *m,char *str){
	char *result;
	char *oob;
	int i,olen,dlen,r,kind,type;
	char sender[MAXIPADDRESSLEN];
	char receiver[MAXIPADDRESSLEN];
	char data[DATA_SIZE];	
	/*init */
	result = NULL;
	memset(sender,0,MAXIPADDRESSLEN);
	memset(receiver,0,MAXIPADDRESSLEN);
	memset(data,0,DATA_SIZE);

	/* Retrieve OOB */
	result = strtok(str,"[");
	if(result == NULL) return (ERROR);
	olen = strlen(result);
	oob = malloc(olen*sizeof(char));
	memset(oob,0,olen);
	sprintf(oob,"%s",result);
	for(i=0;i<olen;i++) if(oob[i]=='|') oob[i] = ' ';

	r = sscanf(oob,"%s %s %d %d",sender
								,receiver
								,&kind
								,&type);
	if (r < 4) return (ERROR);
	/* Retrieve data */
	result = strtok(NULL,"[");
	if(result == NULL) r = sprintf(data,"");
	else r = sprintf(data,"%s",result);
	if(r < 0) return (ERROR);
	
	/* build message */
	if (build_message(m,sender,receiver,kind,type,data) < 0) return (ERROR);
	/* free vars */
	free(oob);
	
	return (OK);
}

/* create an OK reply message */
void make_OK_reply_message(dfs_message *m,const char *reply_to_addr){
	extern char this_address[MAXIPADDRESSLEN];
	build_message(m,this_address,reply_to_addr,REPL_KIND,OK_MSG,"");
}

/* create an ERROR reply message */
void make_ER_reply_message(dfs_message *m,const char *reply_to_addr){
	extern char this_address[MAXIPADDRESSLEN];
	build_message(m,this_address,reply_to_addr,REPL_KIND,ER_MSG,"");
}
/* create an UNKNOWN_MSG reply message */
void make_UNKNOWN_reply_message(dfs_message *m,const char *reply_to_addr){
	extern char this_address[MAXIPADDRESSLEN];
	build_message(m,this_address,reply_to_addr,REPL_KIND,UNKNOWN_MSG,"");
}
/* create an Response to request message */
void make_RRESPONCE_reply_message(dfs_message *m,const char *reply_to_addr,const char *response){
	extern char this_address[MAXIPADDRESSLEN];
	build_message(m,this_address,reply_to_addr,REPL_KIND,RR_MSG,response);
}

/* reply a message with an OK message */
void reply_with_OK_message(dfs_message *m,const char *receiver,char *buffer,int sd){
	int nbytes;
	
	make_OK_reply_message(m,receiver);						
	memset(buffer,0,sizeof(buffer));
	message_to_string(m,buffer);
	write_to_fd(sd,buffer,"Error while Writing");
}

/* reply a message with an ER message */
void reply_with_ER_message(dfs_message *m,const char *receiver,char *buffer,int sd){
	int nbytes;
	
	make_ER_reply_message(m,receiver);						
	memset(buffer,0,sizeof(buffer));
	message_to_string(m,buffer);
	write_to_fd(sd,buffer,"Error while Writing");
}

/* reply a message with an UKNOWN message */
void reply_with_UNKNOWN_message(dfs_message *m,const char *receiver,char *buffer,int sd){
	int nbytes;
	
	make_UNKNOWN_reply_message(m,receiver);						
	memset(buffer,0,sizeof(buffer));
	message_to_string(m,buffer);
	write_to_fd(sd,buffer,"Error while Writing");
}
/* reply a message with a REQUEST RESPONSE message */
void reply_with_RRESPONCE_message(dfs_message *m,const char *receiver,char *buffer,int sd){
	int nbytes;	
	
	make_RRESPONCE_reply_message(m,receiver,buffer);
	memset(buffer,0,sizeof(buffer));
	message_to_string(m,buffer);
	write_to_fd(sd,buffer,"Error while Writing");
}
/* message handler for client msg*/
int handle_in_message(dfs_message *m_in,char *response,int sd){
	char filepath[PATH_MAX];
	int r;
	if(m_in->kind == COMD_KIND){
		/* message is command */
		switch(m_in->type){
			/* dfs_handles */
			case OP_FILE_MSG:
				r = handle_open_file_msg(m_in->data,sd,filepath);
				if(FD_ISSET(sd,&p2p_list)){
					/* transfer file */
				}		
				return (OK == r)?OK_MSG:ER_MSG;
				break;
			break;
			case RD_FILE_MSG:
				printf("[msg handling for type RD_FILE_MSG not not implemented yet!\n]");
				return UNKNOWN_MSG;
				break;
			break;
			case WR_FILE_MSG:
				printf("[msg handling for type WR_FILE_MSG not not implemented yet!\n]");
				return UNKNOWN_MSG;
				break;
			break;
			case CL_FILE_MSG:
				printf("[msg handling for type CL_FILE_MSG not not implemented yet!\n]");
				return UNKNOWN_MSG;
				break;
			break;
			/* administrative */
			case CON_PEER_MSG:
				return (OK == handle_p2p_connection_msg(m_in->data))?OK_MSG:ER_MSG;
				break;
			case DIS_PEER_MSG:
				printf("[msg handling for type DIS_PEER_MSG not not implemented yet!\n]");
				return UNKNOWN_MSG;
				break;
			case UPD_CACHE_MSG:
				printf("[msg handling for type UPD_CACHE_MSG not not implemented yet!\n]");
				return UNKNOWN_MSG;
				break; 
			case CLR_CACHE_MSG:
				printf("[msg handling for type CLR_CACHE_MSG not not implemented yet!\n]");
				return UNKNOWN_MSG;
				break;
			case GET_LOG_MSG:	
				printf("[msg handling for type GET_LOG_MSG not not implemented yet!\n]");
				return UNKNOWN_MSG;
				break;   
			case GET_NEI_MSG:
			   	printf("[msg handling for type GET_NEI_MSG not not implemented yet!\n]");
				return UNKNOWN_MSG;
				break;
			case GET_SFI_MSG:
				return (OK == handle_sharing_connection_msg(m_in->data))?OK_MSG:ER_MSG;
				break;			   
			case REM_SFI_MSG:
				return (OK == handle_remove_msg(m_in->data))?OK_MSG:ER_MSG;
				break;
			case LIS_SFI_MSG:
				return (OK == handle_list_files_msg(response))?RR_MSG:ER_MSG;
				break;
			default:
				break;
		}
	}else if(m_in->kind == DATA_KIND){
		/* mesasge is data */
		printf("[msg handling for DATA_KIND is not yet implemented]\n");
		return (ERROR);
	}else if(m_in->kind == REPL_KIND){
		/* message is reply */
		printf("[msg handling for REPL_KIND is not yet implemented]\n");
		return (ERROR);
	}
}
